﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using Renci.SshNet;
using Renci.SshNet.Sftp;

using eCitizen.eAlerts.Constants;
using eCitizen.DataContracts;

namespace eCitizen.eAlerts.Utilities
{
    public class SftpConnectionManager
    {
        private class SftpServerCredential
        {
            public string ServerAddress { get; set; }
            public int ServerPort { get; set; }
            public string UserName { get; set; }
            public string Password { get; set; }
        }

        private enum ServerConnectionType
        {
            AgencyConnection,
            OneSmsConnection
        }

        #region "ServerCredential"
        #endregion


        private SftpServerCredential _agencyServerInfo;
        private SftpServerCredential _oneSmsServerInfo;

        public SftpConnectionManager()
        {
            LoadCredentials();
        }


        #region "File Transfer from Agency<--->eAlerts, eAlerts<--->OneSms"
        
        // This method is to copy the files from the agency folder to local : i.e: eAlertRequests
        public bool TransferRemoteAgencyFilesToLocal(SftpConfiguration configuration)
        {
            bool isTransferSuccessful = true;

            try
            {
                string serverFilePath = configuration.GetServerInboxFolder();
                string localFilePath = configuration.GetLocalInboxFolder();

                if (!Directory.Exists(localFilePath)) Directory.CreateDirectory(localFilePath);

                SftpClient client = CreateServerConnection(ServerConnectionType.AgencyConnection);

                client.Connect();

                List<SftpFile> files = client.ListDirectory(serverFilePath).ToList();

                foreach (SftpFile file in files)
                {
                    if (!file.IsDirectory)
                    {
                        string localfile = String.Format("{0}/{1}", localFilePath, file.Name);
                        Stream stream = new FileStream(localfile, FileMode.OpenOrCreate);

                        string path = file.FullName;
                        client.DownloadFile(path, stream);

                        stream.Close();

                        file.Delete();
                    }
                }

                client.Disconnect();
            }
            catch (Exception ex)
            {
                // Log
                isTransferSuccessful = false;
            }

            return isTransferSuccessful;
        }

        public bool TransferLocalFilesToOneSms(SftpConfiguration configuration)
        {
            bool isTransferSuccessful = true;

            try
            {
                string localFilePath = configuration.GetLocalSmsInboxFolder();
                string serverFilePath = configuration.GetServerInboxFolder();

                Renci.SshNet.SftpClient client = CreateServerConnection(ServerConnectionType.OneSmsConnection);

                client.Connect();

                List<string> localFiles = Directory.GetFiles(localFilePath, ServiceConstants.FileFilterFormats.OneSmsRequestFileFormat).ToList();

                if (localFiles != null && localFiles.Count > 0)
                {
                    foreach (string localFile in localFiles)
                    {
                        Stream fileData = File.OpenRead(localFile);

                        if (fileData != null && fileData.Length > 0)
                        {
                            string serverFile = String.Format("{0}/{1}", serverFilePath, Path.GetFileName(localFile));
                            client.UploadFile(fileData, serverFile);
                        }

                        fileData.Close();
                        // Don't delete the local files, the files should be moved into Archive
                    }
                }

                client.Disconnect();

            }
            catch (Exception ex)
            {
                isTransferSuccessful = false;
            }

            return isTransferSuccessful;
        }

        public bool TransferOneSmsReportFilesToLocal(SftpConfiguration configuration)
        {
            bool isTransferSuccessful = true;

            string serverFilePath = configuration.GetServerOutboxFolder();
            string localFilePath = configuration.GetLocalSmsOutboxFolder();

            try
            {

                if (!Directory.Exists(localFilePath)) Directory.CreateDirectory(localFilePath);

                Renci.SshNet.SftpClient client = CreateServerConnection(ServerConnectionType.OneSmsConnection);

                client.Connect();

                List<SftpFile> files = client.ListDirectory(serverFilePath).ToList();

                foreach (SftpFile file in files)
                {
                    if (!file.IsDirectory)
                    {
                        string localfile = String.Format("{0}/{1}", localFilePath, file.Name);
                        Stream stream = new FileStream(localfile, FileMode.OpenOrCreate);

                        string path = file.FullName;
                        client.DownloadFile(path, stream);

                        stream.Close();

                        file.Delete();
                    }
                }

                client.Disconnect();
            }
            catch (Exception ex)
            {
                isTransferSuccessful = false;
            }

            return isTransferSuccessful;
        }

        public bool TransferLocalReportFilesToAgency(SftpConfiguration configuration)
        {
            bool isTransferSuccessful = true;

            string localSmsFilePath = configuration.GetLocalSmsOutboxFolder();
            string localFilePath = configuration.GetLocalOutboxFolder();
            string serverFilePath = configuration.GetServerOutboxFolder();


            List<string> localFiles = new List<string>();

            try
            {
                Renci.SshNet.SftpClient client = CreateServerConnection(ServerConnectionType.AgencyConnection);

                client.Connect();

                // 1. Copy Email, Subscriber Report to the Server
                localFiles = Directory.GetFiles(localFilePath).Where(s => ServiceConstants.FileFilterFormats.FullReportFileFormat.ToUpper().Contains(Path.GetExtension(s).ToUpper())).ToList();

                if (localFiles != null && localFiles.Count > 0)
                {
                    foreach (string localFile in localFiles)
                    {
                        Stream fileData = File.OpenRead(localFile);

                        if (fileData != null && fileData.Length > 0)
                        {
                            string serverFile = String.Format("{0}/{1}", serverFilePath, Path.GetFileName(localFile));
                            client.UploadFile(fileData, serverFile);
                        }

                        fileData.Close();
                        // Don't delete the local files, the files should be moved into Archive
                    }
                }


                // 2. Copy Sms Report to the Server
                localFiles = Directory.GetFiles(localSmsFilePath).Where(s => ServiceConstants.FileFilterFormats.FullReportFileFormat.ToUpper().Contains(Path.GetExtension(s).ToUpper())).ToList();

                if (localFiles != null && localFiles.Count > 0)
                {
                    foreach (string localFile in localFiles)
                    {
                        Stream fileData = File.OpenRead(localFile);

                        if (fileData != null && fileData.Length > 0)
                        {
                            string serverFile = String.Format("{0}/{1}", serverFilePath, Path.GetFileName(localFile));
                            client.UploadFile(fileData, serverFile);
                        }

                        fileData.Close();
                        // Don't delete the local files, the files should be moved into Archive
                    }
                }

                client.Disconnect();
            }
            catch (Exception ex)
            {
                isTransferSuccessful = false;
            }

            return isTransferSuccessful;
        }

        public bool TransferLocalErrorLogToAgency(SftpConfiguration configuration)
        {
            bool isTransferSuccessful = true;

            string localFilePath = configuration.GetLocalOutboxFolder();
            string serverFilePath = configuration.GetServerOutboxFolder();


            List<string> localFiles = new List<string>();

            try
            {

                if (!Directory.Exists(localFilePath)) Directory.CreateDirectory(localFilePath);

                Renci.SshNet.SftpClient client = CreateServerConnection(ServerConnectionType.AgencyConnection);

                client.Connect();

                // 1. Copy Email, Subscriber Report to the Server
                localFiles = Directory.GetFiles(localFilePath, ServiceConstants.FileFilterFormats.eAlertsErrorLogFormat).ToList();

                if (localFiles != null && localFiles.Count > 0)
                {
                    foreach (string localFile in localFiles)
                    {
                        Stream fileData = File.OpenRead(localFile);

                        if (fileData != null && fileData.Length > 0)
                        {
                            string serverFile = String.Format("{0}/{1}", serverFilePath, Path.GetFileName(localFile));
                            client.UploadFile(fileData, serverFile);
                        }

                        fileData.Close();
                        // Don't delete the local files, the files should be moved into Archive
                    }
                }

            }
            catch (Exception ex)
            {
                isTransferSuccessful = false;
            }

            return isTransferSuccessful;
        }

        #endregion

        #region "Housekeeping of files on the Server(s)"

        public bool CleanupFilesFromServer(SftpConfiguration configuration)
        {
            bool isSuccessful = true;
            SftpClient clientConnection = null;
            string filePathForHouseKeeping = string.Empty;

            // 1. Clean up the files from Agency Outbox

            clientConnection = CreateServerConnection(ServerConnectionType.AgencyConnection);
            filePathForHouseKeeping = configuration.GetServerOutboxFolder();
            DoHouseKeeping(clientConnection, filePathForHouseKeeping);

            clientConnection = CreateServerConnection(ServerConnectionType.OneSmsConnection);
            DoHouseKeeping(clientConnection, filePathForHouseKeeping);

            return isSuccessful;
        }



        #endregion
        private void LoadCredentials()
        {
            _agencyServerInfo = new SftpServerCredential();
            _agencyServerInfo.ServerAddress = AppKeyConstants.SftpAgencyServerUrl;
            _agencyServerInfo.ServerPort = Int32.Parse(AppKeyConstants.SftpAgencyServerPort);
            _agencyServerInfo.UserName = AppKeyConstants.SftpAgencyServerUserName;
            _agencyServerInfo.Password = AppKeyConstants.SftpAgencyServerPassword;

            _oneSmsServerInfo = new SftpServerCredential();
            _oneSmsServerInfo.ServerAddress = AppKeyConstants.OneSmsAgencyServerUrl;
            _oneSmsServerInfo.ServerPort = Int32.Parse(AppKeyConstants.OneSmsAgencyServerPort);
            _oneSmsServerInfo.UserName = AppKeyConstants.OneSmsAgencyServerUserName;
            _oneSmsServerInfo.Password = AppKeyConstants.OneSmsAgencyServerPassword;
        }

        private SftpClient CreateServerConnection(ServerConnectionType serverConnection)
        {
            SftpClient clientConnection;
            SftpServerCredential serverCredential;

            serverCredential = serverConnection == ServerConnectionType.AgencyConnection ? _agencyServerInfo : _oneSmsServerInfo;

            clientConnection = new SftpClient(serverCredential.ServerAddress, serverCredential.ServerPort, serverCredential.UserName,serverCredential.Password);

            return clientConnection;
        }

        private Stream GetPrivateKeyFile(ServerConnectionType serverConnection)
        {
            string filePath = serverConnection == ServerConnectionType.AgencyConnection ? AppKeyConstants.SftpAgencyPublicKeyFile : AppKeyConstants.OneSmsAgencyPublicKeyFile;
            Stream privateKeyFileData = null;

            privateKeyFileData = File.Open(filePath, FileMode.Open);

            return privateKeyFileData;

        }
        private void DoHouseKeeping(SftpClient clientConnection,string filePathForHouseKeeping)
        {
            clientConnection.Connect();

            List<SftpFile> fileList = new List<SftpFile>();
            int housekeepingValidityMonth = int.Parse(AppKeyConstants.HouseKeepingFileLifeInMonths);
            DateTime fileExpiryDate = DateTime.Now.AddMonths(-housekeepingValidityMonth);

            fileList = clientConnection.ListDirectory(filePathForHouseKeeping).ToList();

            if (fileList != null && fileList.Count > 0)
            {
                foreach (SftpFile serverFile in fileList)
                {
                    if (!serverFile.IsDirectory && (serverFile.LastAccessTime < fileExpiryDate || serverFile.LastWriteTime < fileExpiryDate))
                    {
                        serverFile.Delete();
                    }
                }
            }

            clientConnection.Disconnect();
        }

    }
}
